home *** CD-ROM | disk | FTP | other *** search
/ SPACE 1 / SPACE - Library 1 - Volume 1.iso / program / 168 / library / lib.c < prev    next >
C/C++ Source or Header  |  1988-04-30  |  15KB  |  748 lines

  1. /* 
  2.  * C library for MJC 2.0 - startup, stdio, TOS, malloc 
  3.  * - now cr/nl mapping
  4.  * - fopen handles binary or text options
  5.  * - MAXBUF is now 1024 for speed
  6.  * - exec passes on current process' environment
  7.  */
  8.  
  9. /* max number of args in argv[] */
  10.  
  11. #define MAXARG    50    
  12.  
  13. /* header file for stdio implementation */
  14.  
  15. #define MAXBUF    1024
  16. #define MAXIO    8
  17.  
  18. struct file {
  19.     char    mode;        /* free or open for read/write         */
  20.     char    fd;        /* GEMTOS file descriptor        */
  21.     int    idx;        /* next slot in buf read/written    */
  22.     int    len;        /* length of the buffer            */
  23.     char    buf[MAXBUF];    /* i/o buffer                */
  24. };
  25.  
  26. /* these are the allowed modes */
  27.  
  28. #define FREE    0
  29. #define RD    1
  30. #define WR    2
  31. #define RDWR    3
  32. #define BINARY    4
  33.  
  34. /* these should match what's found in stdio.h, except for FILE */
  35.  
  36. #define FILE    struct file
  37. #define EOF    (-1)
  38. #define NULL    (0L)
  39. #define EOS    ((char)0)
  40.  
  41. /* these are the GEMDOS trap commands */
  42.  
  43. #define CREATE    0x3C
  44. #define OPEN    0x3D
  45. #define CLOSE    0x3E
  46. #define READ    0x3F
  47. #define WRITE    0x40
  48. #define LSEEK    0x42
  49. #define SETBLK    0x4A
  50. #define EXIT    0x4C
  51.  
  52. /* 
  53.  * the c runtime start up routine for ttp processes
  54.  *
  55.  * assumes a startup sttp.s of
  56.  *    . _bstk 2048
  57.  *    . _estk 4
  58.  *    taa 7 6
  59.  *    lll 4 0
  60.  *    sgl _estk
  61.  *    lag _estk 7
  62.  *    jsr _cttp
  63.  */
  64.  
  65. _cttp(tpa) long tpa; {
  66.  
  67.     extern int _argc;
  68.     extern char *environ;
  69.     extern char *_argv[MAXARG];
  70.     extern FILE *stdin, *stdout, *_fopen();
  71.  
  72.     char *b, *w, *in, *out;
  73.     int i;
  74.     long x, *lp;
  75.  
  76.     if (tpa == NULL) { /* this happened to me once; I don't know why */
  77.         _ps("null tpa\n\r");
  78.         return 1;
  79.     }
  80.  
  81.     /* compute size of program, give memory back to TOS */
  82.     lp = tpa;
  83.     x = lp[3] + lp[5] + lp[7] + 0x100;
  84.     if (trap(1, SETBLK, 0, tpa, x))
  85.         exit(-1);
  86.  
  87.     /* parse the command line */
  88.     _argc = 1;
  89.     _argv[0] = "yc";
  90.     environ = (char *) lp[11];
  91.     b = tpa + 0x81;
  92.     in = out = NULL;
  93.  
  94.     while (*b) {
  95.         while (*b && *b <= ' ') b++;
  96.         w = b;
  97.         while (*b && *b > ' ') b++;
  98.         if (*b) *b++ = 0;
  99.         if (*w == '<') in = w+1;
  100.         else if (*w == '>') out = w+1;
  101.         else if (_argc < MAXARG) _argv[_argc++] = w;
  102.     }
  103.     _argv[_argc] = 0L;
  104.  
  105.     /* init stdio and re-direct if necessary */
  106.     _ioinit();
  107.     if (in) {
  108.         if (_fopen(stdin, in, "r") == NULL) 
  109.             _cant(in);
  110.     }
  111.     if (out) {
  112.         if (*out != '>') { /* create */
  113.             if (_fopen(stdout, out, "w") == NULL)
  114.                 _cant(out);
  115.         }
  116.         else    { /* append */
  117.             if (_fopen(stdout, ++out, "a") == NULL)
  118.                 _cant(out);
  119.         }
  120.     }
  121.  
  122.     /* run the program */
  123.     i = main(_argc, _argv, environ);
  124.  
  125.     /* close up shop */
  126.     if (in) fclose(stdin);
  127.     if (out) fclose(stdout);
  128.     exit(i);
  129. }
  130.  
  131. /* initialize standard i/o */
  132.  
  133. _ioinit() {
  134.     int i;
  135.     extern FILE *stdin, *stdout, *stderr;
  136.     extern FILE _iobuf[1];
  137.  
  138.     for (i = 0; i < MAXIO; i++) {
  139.         _iobuf[i].mode = FREE;
  140.         _iobuf[i].idx = _iobuf[i].len = 0;
  141.     }
  142.     stdin = &_iobuf[0];   stdin->fd = 0;
  143.     stdout = &_iobuf[1];  stdout->fd = 1;
  144.     stderr = &_iobuf[2];  stderr->fd = 1;
  145.     stdin->mode = RDWR | BINARY;
  146.     stdout->mode = stderr->mode = RDWR;
  147. }
  148.  
  149. /* trouble redirecting output */
  150.  
  151. _cant(s) char *s; {
  152.     _ps("can't redirect ");
  153.     _ps(s);
  154.     _ps("\n\r");
  155.     exit(1);
  156. }
  157.  
  158. /* exit the program */
  159.  
  160. exit(n) { trap(1, EXIT, n); }
  161.  
  162. /*  execute a program: mode=0 -> load and go; mode=3 -> load and return  */
  163.  
  164. exec(file, args, mode) char *file, *args; int mode; {
  165.     extern char *environ;
  166.     return trap(1, 0x4B, mode, file, args, environ);
  167. }
  168.  
  169. /* get environment variable */
  170.  
  171. char *
  172. getenv(name) char *name; {
  173.     extern char *environ;
  174.     char *p, *q;
  175.     for (p = environ; *p; ) {
  176.         for (q = name; *p++ == *q++; )
  177.             ;
  178.         if (p[-1] == '=' && q[-1] == 0)
  179.             return p;
  180.         while (*p++)
  181.             ;
  182.     }
  183.     return NULL;
  184. }
  185.  
  186. /* data for _cttp */
  187.  
  188. int     _argc;
  189. char     *_argv[MAXARG];
  190. char    *environ;
  191.  
  192. /* data for standard i/o */
  193.  
  194. FILE    _iobuf[MAXIO], *stdin,     *stdout, *stderr;
  195.  
  196. /* get options from command line */
  197.  
  198. extern char    *strchr();
  199. extern char    *optarg;
  200. extern int    optind, opterr, optsubind;
  201.  
  202. getopt(argc, argv, optstr) char *argv[], *optstr; {
  203.     char    *o, c;
  204.  
  205.     if (++optind == argc) return EOF;
  206.  
  207.     o = argv[optind];
  208.  
  209.     if (*o == '-') {
  210.         c = o[++optsubind];
  211.         if (c == '-') return EOF;
  212.         optstr = strchr(optstr, c);
  213.         if (optstr == NULL) {
  214.             if (opterr == 0) {
  215.                 _ps("unknown option: ");
  216.                 _ps(o);
  217.                 _ps("\n\r");
  218.             }
  219.             optsubind = 0;
  220.             return '?';
  221.         }
  222.         if (optstr[1] == ':') {
  223.             optarg = (o[optsubind + 1] != (char)0)
  224.                     ? o + optsubind + 1 : argv[++optind];
  225.             optsubind = 0;
  226.             if (optarg == NULL) {
  227.                 if (opterr == 0) {
  228.                     _ps("missing arg: ");
  229.                     _ps(o);
  230.                     _ps("\n\r");
  231.                 }
  232.                 return '?';
  233.             }
  234.         }
  235.         else if (o[2] != (char)0) {
  236.             optind -= 1;
  237.         }
  238.         return c;
  239.     }
  240.     return EOF;
  241. }
  242.  
  243. char    *optarg;
  244. int    optind, opterr, optsubind;
  245.  
  246. _ps(s) char *s; { while (*s) trap(1, 2, *s++); }
  247.  
  248. /*
  249.  * stdio routines 
  250.  */
  251.  
  252. /* return file descriptor of a stream */
  253.  
  254. fileno(s) FILE *s; { return s->fd; }
  255.  
  256. /* read a stream */
  257.  
  258. fread(buf, sz, n, s) char *buf; FILE *s; {
  259.     int r;
  260.     long nn;
  261.     nn = (long) n * (long) sz;
  262.     if ((r = trap(1, READ, s->fd, nn, buf)) < 0)
  263.         r = 0;
  264.     else    r = r / sz;
  265.     return r;
  266. }
  267.  
  268. /* write on a stream */
  269.  
  270. fwrite(buf, sz, n, s) char *buf; FILE *s; {
  271.     int r;
  272.     long nn;
  273.     nn = (long) n * (long) sz;
  274.     if ((r = trap(1, WRITE, s->fd, nn, buf)) < 0)
  275.         r = 0;
  276.     else    r = r / sz;
  277.     return r;
  278. }
  279.  
  280. /* seek and ye shall find */
  281.  
  282. fseek(s, offset, mode) FILE *s; long offset; {
  283.     lseek(s->fd, offset, mode);
  284. }
  285.  
  286. /* re-open a stream */
  287.  
  288. FILE *
  289. freopen(name, mode, fp) char *name, *mode; FILE *fp; {
  290.     FILE *fopen();
  291.     fclose(fp);
  292.     return fopen(name, mode);
  293. }
  294.  
  295. /* close a stream */
  296.  
  297. fclose(s) FILE *s; {
  298.     if (s != NULL) {
  299.         if ((s->mode & RDWR) == WR) fflush(s);
  300.         if (s->fd > 5) trap(1, CLOSE, s->fd);
  301.         s->mode = FREE;
  302.     }
  303. }
  304.  
  305. /* get a string from a stream */
  306.  
  307. char *
  308. fgets(b, n, f) char *b; int n; FILE *f; {
  309.     int c, i;
  310.     c = getc(f);
  311.     if (c == EOF) return NULL;
  312.     n--;
  313.     for (i = 0; i < n && c != EOF; c = getc(f)) {
  314.         b[i++] = c;
  315.         if (c == '\n') break;
  316.     }
  317.     b[i] = 0;
  318.     return b;
  319. }
  320.  
  321. /* open a stream */
  322.  
  323. FILE *
  324. fopen(name, mode) char *name, *mode; {
  325.     int i;
  326.     FILE *_fopen();
  327.     for (i = 0; i < MAXIO && _iobuf[i].mode != FREE; i++)
  328.         ;
  329.     if (i >= MAXIO) return NULL;
  330.     return _fopen(&_iobuf[i], name, mode);
  331. }
  332.  
  333. FILE *
  334. _fopen(s, name, mode) FILE *s; char *name, *mode; {
  335.     int m, fd;
  336.     if (strcmp(name, "PRT:") == 0) {
  337.         fd = 3;
  338.         m = RDWR;
  339.     }
  340.     else if (strcmp(name, "CON:") == 0) {
  341.         fd = 0;
  342.         m = RDWR;
  343.     }
  344.     else if (strcmp(name, "AUX:") == 0) {
  345.         fd = 2;
  346.         m = RDWR;
  347.     }
  348.     else    {
  349.         if (*mode == 'w') {
  350.             fd = trap(1, CREATE, name, 0);
  351.             m = WR;
  352.         }
  353.         else if (*mode == 'r') {
  354.             fd = trap(1, OPEN, name, 0);
  355.             m = RD;
  356.         }
  357.         else if (*mode == 'a') {
  358.             if ((fd = trap(1, OPEN, name, 1)) < 0)
  359.                 fd = trap(1, CREATE, name, 0);
  360.             else    if (trap(1, LSEEK, 0L, fd, 2) < 0L)
  361.                 fd = -1;
  362.             m = WR;
  363.         }
  364.         else    { /* anything goes here, usually '+' */
  365.             fd = trap(1, OPEN, name, 3);
  366.             m = RDWR;
  367.         }
  368.     }
  369.     if (mode[1] == 'b')
  370.         m |= BINARY;
  371.     if (fd < 0) return NULL;
  372.     s->len = s->idx = 0;
  373.     s->fd = fd;
  374.     s->mode = m;
  375.     return s;
  376. }
  377.  
  378. /* put a string onto the stream */
  379.  
  380. fputs(s, f) char *s; FILE *f; {
  381.     while (*s) putc(*s++, f);
  382. }
  383.  
  384. /* get a string from stdin */
  385.  
  386. char *
  387. gets(b) char *b; {
  388.     int c;
  389.     char *r;
  390.     r = b;
  391.     if ((c = getc(stdin)) == EOF) 
  392.         return NULL;
  393.     while (c != '\n' && c != EOF) {
  394.         *b++ = c;
  395.         c = getc(stdin);
  396.     }
  397.     *b = 0;
  398.     return r;
  399. }
  400.  
  401. /* get a character from standard input */
  402.  
  403. getchar() { return getc(stdin); }
  404.  
  405. /* get a character from a stream, map CR/NL to NL, handle console */
  406.  
  407. getc(s) FILE *s; {
  408.     int i, l, c, r, m;
  409.     if (s == NULL) return EOF;
  410.     m = (s->mode & RDWR);
  411.     if (m == RDWR) {
  412.         l = trap(1, READ, s->fd, (long) 1, s->buf);
  413.         if (l != 1) return EOF;
  414.         i = 0;
  415.     }
  416.     else if (m == RD) {
  417.         i = s->idx;
  418.         while (i >= s->len) {
  419.             l = trap(1, READ, s->fd, (long) MAXBUF, s->buf);
  420.             if (l <= 0) {
  421.                 s->idx = s->len = 0;
  422.                 return EOF;
  423.             }
  424.             s->len = l;
  425.             i = 0;
  426.         }
  427.         s->idx = i + 1;
  428.     }
  429.     else    return EOF;
  430.     c = s->buf[i] & 255;
  431.     if (s->fd == 0) { /* tty input */
  432.         if (c == '\r')
  433.             trap(1, 2, (c = '\n'));
  434.         else if (c == 0x04) /* control D */
  435.             c = EOF;
  436.     }
  437.     if (c == '\r' && !(s->mode & BINARY))
  438.         c = getc(s);
  439.     return c;
  440. }
  441.  
  442. /* output characters to a stream */
  443.  
  444. putchar(c) { putc(c, stdout); }
  445.  
  446. puts(s) char *s; {
  447.     while (*s) putc(*s++, stdout);
  448.     putc('\n', stdout);
  449. }
  450.  
  451. putc(c, s) int c; FILE *s; {
  452.     int i, m, r = 0;
  453.     if (s == NULL) return EOF;
  454.     if (c == '\n' && !(s->mode & BINARY))
  455.         r = putc('\r', s);
  456.     r = 0;
  457.     m = s->mode & RDWR;
  458.     if (m == RDWR) {
  459.         s->buf[0] = c;
  460.         r = trap(1, WRITE, s->fd, (long) 1, s->buf);
  461.     }
  462.     else if (m == WR) {
  463.         if (s->idx == MAXBUF) r = fflush(s);
  464.         s->buf[s->idx] = c;
  465.         s->idx = s->idx + 1;
  466.     }
  467.     else     return EOF;
  468.     return r <= 0 ? EOF : r;
  469. }
  470.  
  471. /* flush out a buffer */
  472.  
  473. fflush(s) FILE *s; {
  474.     int r;
  475.     if (s->idx > 0) 
  476.         r = trap(1, WRITE, s->fd, (long) s->idx, s->buf);
  477.     s->idx = 0;
  478.     return r <= 0 ? EOF : r;
  479. }
  480.  
  481. /* 
  482.  * TOS routines 
  483.  */
  484.  
  485. /* duplicate a file descriptor */
  486.  
  487. dup(fd) { return trap(1, 0x45, fd); }
  488.  
  489. dup2(fold, fnew) { return trap(1, 0x46, fold, fnew); }
  490.  
  491. /* get current directory: drive=0 -> current drive, drive=1 -> A:, etc */
  492.  
  493. getdir(buf, drive) char *buf; {
  494.     return trap(1, 0x47, buf, drive);
  495. }
  496.  
  497. /* 
  498.  * list the disk directory
  499.  *    pat != NULL - set the DTA buffer, do an SFIRST
  500.  *    pat == NULL - do a SNEXT
  501.  */
  502.  
  503. listdir(pat, buf, mode) char *pat, *buf; {
  504.     if (pat) {
  505.         trap(1, 0x1A, buf);
  506.         return trap(1, 0x4E, pat, mode);
  507.     }
  508.     else    return trap(1, 0x4F);
  509. }
  510.  
  511. /* seek to a position in a file */
  512.  
  513. lseek(fd, offset, mode) int fd; long offset; int mode; {
  514.     return trap(1, 0x42, offset, fd, mode);
  515. }
  516.  
  517. /* unlink a file */
  518.  
  519. unlink(name) char *name; { return trap(1, 0x41, name); }
  520.  
  521. /* close a file */
  522.  
  523. close(fd) { trap(1, 0x3E, fd); }
  524.  
  525. /* create a file */
  526.  
  527. creat(f, m) char *f; {
  528.     return trap(1, 0x3C, f, m);
  529. }
  530.  
  531. /* open a file */
  532.  
  533. open(f, m) char *f; {
  534.     return trap(1, 0x3D, f, m);
  535. }
  536.  
  537. /* read a file */
  538.  
  539. read(fd, buf, sz) int fd, sz; char *buf; {
  540.     return trap(1, 0x3F, fd, (long) sz, buf);
  541. }
  542.  
  543. /* unix-like write system call */
  544.  
  545. write(fd, buf, sz) int fd, sz; char *buf; {
  546.     return trap(1, 0x40, fd, (long) sz, buf);
  547. }
  548.  
  549. /* 
  550.  * chmod(name, mode)
  551.  * mode = 0x00 - normal file (read/write)
  552.  *        0x01 - read only file
  553.  *        0x02 - hidden file
  554.  *        0x04 - system file
  555.  *        0x08 - file is volume label
  556.  *        0x10 - file is a subdirectory
  557.  *        0x20 - file is written and closed correctly
  558.  */
  559.  
  560. chmod(name, mode) char *name; int mode; {
  561.     return trap(1, 0x43, name, mode, 0);
  562. }
  563.  
  564. /* malloc, free, realloc: dynamic memory allocation */
  565.  
  566. #define MAXHUNK    20000
  567.  
  568. struct header {
  569.     struct header *next;
  570.     long size;
  571. };
  572.  
  573. char *
  574. realloc(r, n) struct header *r; unsigned n; {
  575.     struct header *p, *q;
  576.     char *malloc();
  577.     long *src, *dst;
  578.     long sz;
  579.  
  580.     p = r - 1;
  581.     sz = (n + sizeof(struct header) + 7) & ~7;
  582.  
  583.     if (p->size > sz) { /* block too big, split in two */
  584.         q = ((long) p) + sz;
  585.         q->size = p->size - sz;
  586.         free(q + 1);
  587.         p->size = sz;
  588.     }
  589.     else if (p->size < sz) { /* block too small, get new one */
  590.         dst = q = malloc(n);
  591.         if (q != NULL) {
  592.             src = r;
  593.             n = p->size - sizeof(struct header);
  594.             while (n > 0) {
  595.                 *dst++ = *src++;
  596.                 n -= sizeof(long);
  597.             }
  598.         }
  599.         free(r);
  600.         r = q;
  601.     }
  602.     /* else current block will do just fine */
  603.  
  604.     return r;
  605. }
  606.  
  607. char *
  608. calloc(n, sz) unsigned n, sz; {
  609.     char *r, *s, *malloc();
  610.     unsigned total;
  611.  
  612.     total = n * sz;
  613.     if ((r = s = malloc(total)) != NULL) {
  614.         while (total--)
  615.             *s++ = 0;
  616.     }
  617.     return r;
  618. }
  619.  
  620. char *
  621. malloc(n) unsigned n; {
  622.     extern struct header _base;
  623.     struct header *p, *q;
  624.     long sz, asz;
  625.  
  626.     /* add a header to required size and round up */
  627.     sz = (n + sizeof(struct header) + 7) & ~7;
  628.  
  629.     /* look for first block big enough in free list */
  630.     p = &_base;
  631.     q = _base.next;
  632.     while (q != NULL && q->size < sz) {
  633.         p = q;
  634.         q = q->next;
  635.     }
  636.  
  637.     /* if not enough memory, get more from the system */
  638.     if (q == NULL) {
  639.         asz = (sz < MAXHUNK) ? MAXHUNK : sz;
  640.         q = trap(1, 0x48, asz);
  641.         if (((long)q) < 0L) /* no more memory */
  642.             return NULL;
  643.         p->next = q;
  644.         q->size = asz;
  645.         q->next = NULL;
  646.     }
  647.         
  648.     if (q->size > sz + sizeof(struct header)) { /* chop it up */
  649.         q->size -= sz;
  650.         q = ((long) q) + q->size;
  651.         q->size = sz;
  652.     }
  653.     else    { /* unlink from free list */
  654.         p->next = q->next;
  655.     }
  656.     
  657.     /* skip over header, hope they don't touch it */
  658.     return ++q;
  659. }
  660.  
  661. free(r) struct header *r; {
  662.     extern struct header _base;
  663.     struct header *p, *q, *t;
  664.  
  665.     /* move back to uncover the header */
  666.     r--;
  667.  
  668.     /* find where to insert it */
  669.     p = &_base;
  670.     q = _base.next;
  671.     while (q != NULL && q < r) {
  672.         p = q;
  673.         q = q->next;
  674.     }
  675.  
  676.     /* merge after if possible */
  677.     t = ((long) r) + r->size;
  678.     if (q != NULL && t >= q) {
  679.         r->size += q->size;
  680.         q = q->next;
  681.     }
  682.     r->next = q;
  683.     
  684.     /* merge before if possible, otherwise link it in */
  685.     t = ((long) p) + p->size;
  686.     if (t >= r) {
  687.         p->size += r->size;
  688.         p->next = r->next;
  689.     }
  690.     else    p->next = r;
  691. }
  692.  
  693. struct header _base = { NULL, 0L };
  694.  
  695. /* a UNIX style time command */
  696.  
  697. extern int _ma[];
  698.  
  699. long
  700. time(tloc) long *tloc; {
  701.     int    n, hms, y, m, d;
  702.     long    t;
  703.  
  704.     n = getdate();
  705.     y = (n >> 9) & 127; m = (n >> 5) & 15; d = n & 31;
  706.     hms = gettime();
  707.     t = (1460 * y) / 4 + ((y % 4) ? 1 : 0) + _ma[m] + d;
  708.     t = 2L * (long)(hms & 31)
  709.         + 60L * (long)((hms >> 5) & 63)
  710.         + 3600L * (24L * t + (long)((hms >> 11) & 31));
  711.     if (tloc != NULL) *tloc = t;
  712.     return t;
  713. }
  714.  
  715. getdate() { return trap(1, 0x2A); }
  716.  
  717. gettime() { return trap(1, 0x2C); }
  718.  
  719. int _ma[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
  720.  
  721. /* setjmp/longjmp thanks to Bruce Szablak, use setjmp.h! */
  722.  
  723. setjmp(buf) char **buf; {
  724.     asm( lll 8 0);
  725.     asm( tda 0 0); /* a0 has pointer to buffer */
  726.     asm( tad 6 0); /* d0 has current link pointer */
  727.     asm( sol 0 0 0); /* save clp */
  728.     asm( lol 6 0 0); /* d0 has old link pointer */
  729.     asm( sol 0 4 0); /* save olp */
  730.     asm( lol 6 4 0); /* d0 has return address */
  731.     asm( sol 0 8 0); /* save ret */
  732.     return 0;
  733. }
  734.  
  735. longjmp(buf, rc) char **buf; {
  736.     asm( lll 8 0);
  737.     asm( tda 0 0); /* buf in a0 */
  738.     asm( llw 12 0); /* rc in d0 */
  739.     asm( lol 0 0 1); /* current link pointer */
  740.     asm( tda 1 6); /* now in a6 */
  741.     asm( lol 0 4 1); /* old link pointer */
  742.     asm( sll 1 0); /* now on stack */
  743.     asm( lol 0 8 1); /* return address */
  744.     asm( sll 1 4); /* now on stack */
  745.     return; /* longjmp! */
  746. }    
  747.  
  748.